package com.huntech.log.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huntech.common.constant.RegularFormatConstant;
import com.huntech.log.domain.LogRecord;
import com.huntech.log.mapper.LogMapper;
import com.huntech.log.service.LogService;
import com.huntech.log.util.LogFileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class LogServiceImpl implements LogService {

    /**
     * 批次大小
     */
    private static final int BATCH_SIZE = 200;
    private static final int BATCH_MESSAGE_LENGTH = 16000;

    @Autowired
    private LogMapper logMapper;

    /**
     * 批量插入日志
     */
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    @Override
    public void insertBatch(MultipartFile logFile) {
        if (logFile.isEmpty()) {
            return;
        }
        // 获取服务名称
        String serverName = LogFileUtil.getServerName(logFile);

        // 处理文件
        List<LogRecord> logRecords = new ArrayList<>(BATCH_SIZE);
        Pattern pattern = Pattern.compile(RegularFormatConstant.LOG_REGEX);
        DateTimeFormatter logFormatter = DateTimeFormatter.ofPattern(RegularFormatConstant.TS_FORMAT_LOG);
        DateTimeFormatter dbFormatter = DateTimeFormatter.ofPattern(RegularFormatConstant.TS_FORMAT_DB);

        try (BufferedReader br = new BufferedReader(new InputStreamReader(logFile.getInputStream()))) {
            String line;
            LogRecord currentRecord = null;
            int lineCount = 0;
            int timeCount = 0;
            int logCount = 0;
            int messageCount = 0;
            LocalDateTime currentTime = null;

            while ((line = br.readLine()) != null) {
                lineCount++;
                Matcher matcher = pattern.matcher(line);
                if (matcher.matches()) {
                    // 保存前一个日志条目
                    if (currentRecord != null) {
                        logRecords.add(currentRecord);
                        messageCount += currentRecord.getLogMessage().length();
                    }

                    // 解析新日志条目
                    try {
                        // 提取匹配组
                        String timestamp = matcher.group(1);
                        String logLevel = matcher.group(2);
                        int pid = Integer.parseInt(matcher.group(3));
                        String threadName = matcher.group(4);
                        String logSource = matcher.group(5);
                        String logMessage = LogFileUtil.truncateLogMessage(LogFileUtil.escapeSpecialChars(matcher.group(6)), lineCount);

                        // 转换时间戳格式并添加时间以区分
                        LocalDateTime logDateTime = LocalDateTime.parse(timestamp, logFormatter);
                        String dbFormatted = logDateTime.format(dbFormatter);
                        LocalDateTime dbDateTime = LocalDateTime.parse(dbFormatted, dbFormatter);
                        if (currentTime != null && currentTime.isEqual(dbDateTime)) {
                            timeCount++;
                            dbDateTime = dbDateTime.plusNanos(timeCount * 1000L);
                        } else {
                            currentTime = dbDateTime;
                            timeCount = 0;
                        }
                        dbDateTime = dbDateTime.plusNanos(1);
                        Timestamp ts = Timestamp.valueOf(dbDateTime);

                        // 去掉threadName前的空格
                        int index = threadName.lastIndexOf(" ");
                        if (index != -1) {
                            threadName = threadName.substring(index + 1);
                        }
                        currentRecord = new LogRecord(ts, logLevel, pid, threadName, logSource, logMessage, null);
                    } catch (RuntimeException e) {
                        log.error("解析错误 （行 {}）：{} --- {}", lineCount, line, e.getMessage());
                        currentRecord = null;
                    }

                } else {
                    // 处理多行日志（堆栈追踪等）
                    if (currentRecord != null) {
                        String newMessage = currentRecord.getLogMessage() + "\n" + line;
                        currentRecord.setLogMessage(LogFileUtil.truncateLogMessage(newMessage, lineCount));
                    } else if (StringUtils.hasText(line)) {
                        log.error("未识别格式 （行 {}）：{}", lineCount, line);
                    }
                }

                // 批量保存
                if (logRecords.size() >= BATCH_SIZE || messageCount >= BATCH_MESSAGE_LENGTH) {
                    logCount += logRecords.size();
                    logMapper.createAndInsertBatch(serverName, logRecords);
                    log.info("已插入批次日志共{}条", logCount);
                    logRecords.clear();
                    messageCount = 0;
                }
            }
            // 添加最后一条日志
            if (currentRecord != null) {
                logRecords.add(currentRecord);
            }

            // 保存剩余日志
            if (!logRecords.isEmpty()) {
                logCount += logRecords.size();
                logMapper.createAndInsertBatch(serverName, logRecords);
                log.info("插入完成，共插入日志{}条", logCount);
            }

        } catch (IOException e) {
            log.error("文件读取错误: {}", e.getMessage());
        }
    }

    /**
     * 根据tag，分页查询时间段日志
     */
    @Override
    public PageInfo<LogRecord> select(String startTime, String endTime, String logLevel, int pageNum, int pageSize) {
        if(startTime != null)
            startTime += "+08:00";
        if(endTime != null)
            endTime += "+08:00";

        PageHelper.startPage(pageNum, pageSize);
        List<LogRecord> logRecords = logMapper.selectLogByTimeAndLevel(startTime,endTime,logLevel);
        return new PageInfo<>(logRecords);
    }
}
